//////////////////////////////////////////////////////////////////////////////

#include "Thread.h"		// simplescalar + thread functional simulator(s)
#include "parameters.h"		// simulator configuration

//////////////////////////////////////////////////////////////////////////////

#include "bpred_interface.h"	// referenced by fetch unit
#include "memory_macros.h"	// referenced by memory system
#include "histogram.h"		// referenced by fetcn unit and memory system
#include "cache.h"		//	"
#include "dcache.h"		//	"

//////////////////////////////////////////////////////////////////////////////

#include "payload.h"		// instruction payload buffer

#include "pipeline_register.h"	// PIPELINE REGISTERS

#include "fetch_queue.h"	// FETCH QUEUE

#include "renamer.h"		// REGISTER RENAMER + REGISTER FILE

#include "lane.h"		// EXECUTION LANES

#include "issue_queue.h"	// ISSUE QUEUE

#include "mem_interface.h"	// MEMORY SYSTEM

#include "processing_element.h" 	//processing element

#include "trace_queue.h"		//trace level active list

//////////////////////////////////////////////////////////////////////////////

#define TOTAL_FP_REGS		32
#define TOTAL_GP_INT_REGS	32
#define TOTAL_INT_REGS		35

#define HI_ID_NEW		32
#define LO_ID_NEW		33
#define FCC_ID_NEW		34

#define LOCAL_FP_REGS		14
#define LOCAL_INT_REGS		17
#define LOCAl_TOTAL_REGS	31

#define LOCAL_REGISTER		1
#define GLOBAL_REGISTER		2

#define TOTAL_PROCESSING_ELEMENTS 4

#define MAX_WAKE_UP_DELAY	2      //Time taken for the across PE bypass

//////////////////////////////////////////////////////////////////////////////

#define IS_BRANCH(flags)	((flags) & (F_CTRL))
#define IS_LOAD(flags)          ((flags) & (F_LOAD))
#define IS_STORE(flags)         ((flags) & (F_STORE))
#define IS_MEM_OP(flags)        ((flags) & (F_MEM))

//////////////////////////////////////////////////////////////////////////////

#define BIT_IS_ZERO(x,i)	(((x) & (((unsigned long long)1) << i)) == 0)
#define BIT_IS_ONE(x,i)		(((x) & (((unsigned long long)1) << i)) != 0)
#define SET_BIT(x,i)		(x |= (((unsigned long long)1) << i))
#define CLEAR_BIT(x,i)		(x &= ~(((unsigned long long)1) << i))

//////////////////////////////////////////////////////////////////////////////

typedef struct{
	bool valid;
	unsigned int phys_reg;
	int time_to_go;
}readyRegQueueType;


class processor {
private:
public:
	/////////////////////////////////////////////////////////////
	// Instruction payload buffer.
	/////////////////////////////////////////////////////////////
	payload	PAY;

	/////////////////////////////////////////////////////////////
	// Pipeline widths.
	/////////////////////////////////////////////////////////////
	unsigned int fetch_width;	// fetch, decode width
	unsigned int dispatch_width;	// rename, dispatch width
	unsigned int issue_width;	// issue width (number of universal execution lanes)
	unsigned int retire_width;	// retire width
	unsigned int num_pe;		//number of processing elements

	/////////////////////////////////////////////////////////////
	// Fetch unit.
	/////////////////////////////////////////////////////////////
	unsigned int pc;		// Speculative program counter.

	SS_TIME_TYPE next_fetch_cycle;	// Support for I$ miss stalls.
	bool wait_for_trap;		// Needed to override perfect branch prediction after fetching a syscall.
	bpred_interface BP;		// Branch predictor.
	CacheClass IC;			// Instruction cache.

	unsigned int branch_miss_pc;	//PC where branch misprediction occurs
	unsigned int branch_target_pc;  //actual target
	bool misprediction;				// flag

	unsigned int exception_post_service_pc;
	unsigned int exception_new_trace_length;
	bool exception_status;
	bool service_exception;
	/////////////////////////////////////////////////////////////
	// Pipeline register between the Fetch and Decode Stages.
	/////////////////////////////////////////////////////////////
	pipeline_register *DECODE;

	/////////////////////////////////////////////////////////////
	// Fetch Queue between the Decode and Rename Stages.
	/////////////////////////////////////////////////////////////
	fetch_queue FQ;

	/////////////////////////////////////////////////////////////
	// Pipeline register between the Rename1 and Rename2
	// sub-stages (within the Rename Stage).
	/////////////////////////////////////////////////////////////
	pipeline_register *RENAME2;

	/////////////////////////////////////////////////////////////
	// Register renaming modules.
	/////////////////////////////////////////////////////////////
	renamer *REN_INT;
	renamer *REN_FP;


	/////////////////////////////////////////////////////////////
	// Pipeline register between the Rename and Dispatch Stages.
	/////////////////////////////////////////////////////////////
	pipeline_register *DISPATCH;

	/////////////////////////////////////////////////////////////
	// Issue Queues.
	/////////////////////////////////////////////////////////////
	//issue_queue IQ_INT;
	//issue_queue IQ_FP;

	/////////////////////////////////////////////////////////////
	// Execution Lanes.
	/////////////////////////////////////////////////////////////
	//lane *Execution_Lanes;
	/////////////////////////////////////////////////////////////
	// Trace Level active list
	/////////////////////////////////////////////////////////////
	trace_queue TQ;

	/////////////////////////////////////////////////////////////
	// Processing Elements.
	/////////////////////////////////////////////////////////////
	processing_element **PE;

	/////////////////////////////////////////////////////////
	//// Ready register queue
	/////////////////////////////////////////////////////////
	readyRegQueueType *ready_reg_int, *ready_reg_fp;
	unsigned int readyRegQueMaxEntries;

	/////////////////////////////////////////////////////////////
	// Load and Store Unit.
	/////////////////////////////////////////////////////////////
	mem_interface LSU;


	//////////////////////
	// PRIVATE FUNCTIONS
	//////////////////////

	void copy_reg();
	void agen(unsigned int index);
	void alu(unsigned int index);
	void squash_complete(unsigned int offending_PC);
	void squash_complete_trace(unsigned int offending_PC);
	void resolve(unsigned int branch_ID, bool correct);
	void checker();
	void check_single(SS_WORD_TYPE proc, SS_WORD_TYPE func, char *desc);
	void check_double(SS_WORD_TYPE proc0, SS_WORD_TYPE proc1, SS_WORD_TYPE func0, SS_WORD_TYPE func1, char *desc);

	int preRenamer(unsigned int *indices, unsigned int traceWidth);

	// To model delayed wake up in the issue queues across multiple PEs use this function *before* schedule() is called every cycle.
	int wakeup_instrutions();
	void add_to_readyQ_int(unsigned int phys_reg, int time_to_go);
	void add_to_readyQ_fp(unsigned int phys_reg, int time_to_go);



	// The thread id.
	unsigned int Tid;

	// The simulator cycle.
	SS_TIME_TYPE cycle;

	// Number of instructions retired.
	unsigned int num_insn;
	unsigned int num_insn_split;

#if 0
	unsigned int BREAKPOINT_TIME;
#endif

	processor(unsigned int fq_size,
			unsigned int num_chkpts,
			unsigned int rob_size,
			unsigned int iq_size,
			unsigned int lq_size,
			unsigned int sq_size,
			unsigned int fetch_width,
			unsigned int dispatch_width,
			unsigned int issue_width,
			unsigned int retire_width,
			unsigned int Tid);

	// Functions for pipeline stages.
	void fetch();
	void decode();
	void rename1();
	void rename2();
	void trace_dispatch();
	void schedule();
	void register_read(unsigned int lane_number);
	void execute(unsigned int lane_number);
	void writeback(unsigned int lane_number);
	void retire();
	
	void dispatch();

	//Branch recovery related functions

	void set_pc(unsigned int starting_pc);
	void set_mispredict_param(unsigned int mispredicted_pc, unsigned int target_pc);
	void set_exception_param(unsigned int no_of_inst, unsigned int offending_PC);


	// Miscellaneous other functions.
	void next_cycle();
	void stats(FILE *fp);
	void skip(unsigned int skip_amt);
};

